import 'package:dio/dio.dart';
import 'package:get/get.dart' hide Response;
import '../../services/token_service.dart';
import '../../middlewares/request_tracing_middleware.dart';
import 'package:flutter/foundation.dart';
import '../../routes/app_routes.dart';

/// HTTP客户端封装
/// 
/// 基于Dio的HTTP客户端，提供了以下功能：
/// 1. 统一的请求/响应拦截器
/// 2. 自动添加授权token
/// 3. 统一错误处理
/// 4. 美化的日志输出
/// 5. 支持GET, POST, PUT, DELETE等方法
/// 6. 请求追踪（控制器和页面来源）
/// 
/// 使用示例:
/// ```dart
/// final HttpClient _httpClient = HttpClient();
/// 
/// // GET请求
/// final response = await _httpClient.get('/product/product/list');
/// 
/// // POST请求
/// await _httpClient.post('/device', data: {'name': 'device1'});
/// ```
class HttpClient {
  static final HttpClient _instance = HttpClient._internal();
  late Dio dio;
  
  // 确保在发布模式下也输出关键日志
  static bool forceDebugLog = true;
  
  static const String _baseUrl = 'http://47.120.9.38:32075';
  
  // 日志样式常量
  static const String _logPrefix = '🌐 ';
  static const String _startLine = '┌────────────────────────────────────────────────────────────────';
  static const String _endLine = '└────────────────────────────────────────────────────────────────';
  static const String _midLine = '├────────────────────────────────────────────────────────────────';
  static const String _level1 = '│ ';
  static const String _level2 = '│ ➙ ';
  
  // 日志配置
  // enableLogTruncate: 是否启用日志截断功能，启用后超长响应数据将被截断显示
  // maxLogLength: 日志最大显示长度，超过此长度的部分将被截断
  // 如需查看完整响应数据，可将enableLogTruncate设为false或增大maxLogLength值
  static bool enableLogTruncate = true;  // 是否截断日志
  static int maxLogLength = 10000;         // 日志最大长度
  
  /// 工厂构造函数
  /// 
  /// 使用单例模式，确保整个应用只有一个HttpClient实例
  /// Provider类通过 HttpClient() 调用此构造函数获取实例
  /// 
  /// @return HttpClient实例
  factory HttpClient() => _instance;
  
  HttpClient._internal() {
    logInfo('【HTTP初始化】创建HttpClient实例');
    logInfo('【HTTP初始化】当前运行模式: ${kReleaseMode ? "发布模式" : "调试模式"}');
    logInfo('【HTTP初始化】服务器地址: $_baseUrl');
    
    BaseOptions options = BaseOptions(
      baseUrl: _baseUrl,
      connectTimeout: const Duration(milliseconds: 15000),
      receiveTimeout: const Duration(milliseconds: 15000),
      headers: {
        'Content-Type': 'application/json; charset=utf-8',
      },
    );
    
    dio = Dio(options);
    
    // 添加请求追踪中间件（记录请求发起的控制器和页面）
    // 放在最前面，确保能捕获完整的调用栈
    dio.interceptors.add(RequestTracingMiddleware());
    
    // 默认启用关键API路径的调试（方便排查问题）
    if (kDebugMode || forceDebugLog) {
      setRequestTracing(
        enable: true,
        paths: [
          '/system/login',
          '/system/user/profile',
          '/data/alert_log/list',
          '/device/device/list',
          '/product/product/list',
        ]
      );
    }
    
    // Add interceptors
    dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        // 添加日志输出
        _printRequestLog(options);
        
        // 记录登录请求的详细信息
        if (options.path.contains('/login')) {
          logInfo('【登录请求】开始发送登录请求');
          logInfo('【登录请求】请求URL: ${options.uri}');
          logInfo('【登录请求】请求方法: ${options.method}');
          if (options.data != null) {
            // 不打印密码，只记录其长度
            var safeData = {...options.data as Map<String, dynamic>};
            if (safeData.containsKey('password')) {
              safeData['password'] = '***已隐藏,长度:${safeData['password']?.length ?? 0}***';
            }
            logInfo('【登录请求】登录参数: $safeData');
          }
        }
        
        // Get token from TokenService
        String? token = _getToken();
        if (token != null && token.isNotEmpty) {
          options.headers['Authorization'] = 'Bearer $token';
        }
        return handler.next(options);
      },
      onResponse: (response, handler) {
        // 添加日志输出
        _printResponseLog(response);
        
        // 记录登录响应的详细信息
        if (response.requestOptions.path.contains('/login')) {
          logInfo('【登录响应】收到登录响应');
          logInfo('【登录响应】状态码: ${response.statusCode}');
          logInfo('【登录响应】响应码: ${response.data['code']}');
          logInfo('【登录响应】消息: ${response.data['msg']}');
        }
        
        // 处理业务响应码
        if (response.data['code'] != 200) {
          throw DioException(
            requestOptions: response.requestOptions,
            response: response,
            error: response.data['msg'],
          );
        }
        return handler.next(response);
      },
      onError: (DioException e, handler) {
        // 添加错误日志
        _printErrorLog(e);
        
        // 添加登录错误的详细日志
        if (e.requestOptions.path.contains('/login')) {
          logInfo('【登录错误】登录请求失败');
          logInfo('【登录错误】错误类型: ${e.type}');
          logInfo('【登录错误】错误信息: ${e.message}');
          if (e.response != null) {
            logInfo('【登录错误】状态码: ${e.response?.statusCode}');
            logInfo('【登录错误】响应数据: ${e.response?.data}');
          }
        }
        
        // 处理401错误（未授权、Token过期）
        if (e.response?.statusCode == 401) {
          logInfo('【授权错误】检测到401未授权错误，正在清除令牌并跳转登录页面...');
          
          // 清除token
          if (Get.isRegistered<TokenService>()) {
            Get.find<TokenService>().clearToken();
          }
          
          // 重定向到登录页面
          // 避免重复跳转
          if (Get.currentRoute != Routes.login) {
            Get.offAllNamed(Routes.login);
          }
        }
        
        return handler.next(e);
      },
    ));
  }
  
  /// 通用日志输出方法，确保在发布模式下也能看到关键日志
  void logInfo(String message) {
    if (kDebugMode || forceDebugLog) {
      debugPrint('$_logPrefix $message');
    }
  }
  
  /// 打印HTTP请求日志
  /// 
  /// 以美观的格式打印HTTP请求的详细信息，包括：
  /// - URL和方法
  /// - 请求头
  /// - 查询参数
  /// - 请求数据
  /// 
  /// @param options 请求选项
  void _printRequestLog(RequestOptions options) {
    if (!kDebugMode && !forceDebugLog) return;
    
    debugPrint(_startLine);
    debugPrint('$_level1$_logPrefix 🚀 HTTP 请求 | ${DateTime.now()}');
    debugPrint(_midLine);
    debugPrint('$_level1${options.method} ${options.uri}');
    
    if (options.headers.isNotEmpty) {
      debugPrint('$_level1📋 请求头:');
      options.headers.forEach((key, value) {
        debugPrint('$_level2$key: $value');
      });
    }
    
    if (options.queryParameters.isNotEmpty) {
      debugPrint('$_level1🔍 查询参数:');
      options.queryParameters.forEach((key, value) {
        debugPrint('$_level2$key: $value');
      });
    }
    
    if (options.data != null) {
      debugPrint('$_level1📦 请求数据:');
      debugPrint('$_level2${options.data}');
    }
    
    debugPrint(_endLine);
  }
  
  /// 打印HTTP响应日志
  /// 
  /// 以美观的格式打印HTTP响应的详细信息，包括：
  /// - 状态码和状态消息
  /// - 请求URL和方法
  /// - 响应数据（可配置是否截断）
  /// 
  /// @param response HTTP响应对象
  void _printResponseLog(Response response) {
    if (!kDebugMode && !forceDebugLog) return;
    
    debugPrint(_startLine);
    debugPrint('$_level1$_logPrefix ✅ HTTP 响应 | ${DateTime.now()}');
    debugPrint(_midLine);
    debugPrint('$_level1${response.statusCode} ${response.statusMessage} | ${response.requestOptions.method} ${response.requestOptions.uri}');
    
    if (response.data != null) {
      debugPrint('$_level1📄 响应数据:');
      final data = response.data.toString();
      // 根据日志配置决定是否截断响应数据
      if (enableLogTruncate && data.length > maxLogLength) {
        debugPrint('$_level2${data.substring(0, maxLogLength)}...(已截断,完整长度:${data.length})');
      } else {
        debugPrint('$_level2$data');
      }
    }
    
    debugPrint(_endLine);
  }
  
  /// 打印HTTP错误日志
  /// 
  /// 以美观的格式打印HTTP错误的详细信息，包括：
  /// - 错误信息
  /// - 请求URL和方法
  /// - 查询参数
  /// - 请求数据
  /// - 响应状态码和数据（如果有）
  /// 
  /// @param e Dio异常对象
  void _printErrorLog(DioException e) {
    if (!kDebugMode && !forceDebugLog) return;
    
    debugPrint(_startLine);
    debugPrint('$_level1$_logPrefix ❌ HTTP 错误 | ${DateTime.now()}');
    debugPrint(_midLine);
    debugPrint('$_level1🔴 错误信息: ${e.message}');
    debugPrint('$_level1🔴 错误类型: ${e.type}');
    debugPrint('$_level1🌐 请求URL: ${e.requestOptions.uri}');
    debugPrint('$_level1📋 请求方法: ${e.requestOptions.method}');
    
    if (e.requestOptions.queryParameters.isNotEmpty) {
      debugPrint('$_level1🔍 查询参数:');
      e.requestOptions.queryParameters.forEach((key, value) {
        debugPrint('$_level2$key: $value');
      });
    }
    
    if (e.requestOptions.data != null) {
      debugPrint('$_level1📦 请求数据:');
      debugPrint('$_level2${e.requestOptions.data}');
    }
    
    if (e.response != null) {
      debugPrint('$_level1🔢 状态码: ${e.response?.statusCode}');
      debugPrint('$_level1📄 响应数据:');
      if (e.response?.data != null) {
        final data = e.response!.data.toString();
        // 根据日志配置决定是否截断错误响应数据
        if (enableLogTruncate && data.length > maxLogLength) {
          debugPrint('$_level2${data.substring(0, maxLogLength)}...(已截断,完整长度:${data.length})');
        } else {
          debugPrint('$_level2$data');
        }
      }
    }
    
    debugPrint(_endLine);
  }
  
  /// 获取当前用户的授权令牌
  /// 
  /// 从TokenService中获取当前保存的令牌
  /// 如果TokenService未注册或令牌不存在，返回null
  /// 
  /// @return 授权令牌或null
  String? _getToken() {
    if (Get.isRegistered<TokenService>()) {
      return Get.find<TokenService>().getToken();
    }
    return null;
  }
  
  // GET请求
  // path: API路径，使用完整路径如"/product/product/list"
  // params: 查询参数，会自动添加到URL中
  // options: Dio请求选项，可自定义headers等
  Future<dynamic> get(
    String path, {
    Map<String, dynamic>? params,
    Options? options,
  }) async {
    try {
      // 特殊日志处理 - 告警日志API
      final bool isAlertLogApi = path.contains('alert_log');
      if (isAlertLogApi) {
        debugPrint('【告警日志】准备发送GET请求到: $path');
        debugPrint('【告警日志】请求参数: $params');
        debugPrint('【告警日志】HttpClient实例: $hashCode');
      }
      
      Response response = await dio.get(
        path,
        queryParameters: params,
        options: options,
      );
      
      // 特殊日志处理 - 告警日志API
      if (isAlertLogApi) {
        debugPrint('【告警日志】请求成功，状态码: ${response.statusCode}');
        if (response.data != null) {
          debugPrint('【告警日志】响应码: ${response.data['code']}');
          debugPrint('【告警日志】消息: ${response.data['msg']}');
          if (response.data['rows'] != null) {
            debugPrint('【告警日志】记录数: ${(response.data['rows'] as List?)?.length ?? 0}');
          } else {
            debugPrint('【告警日志】无数据记录');
          }
        }
      }
      
      // 设备相关API的调试信息
      if (path.contains('/device/') && path.contains('/')) {
        // 检查是否包含数字参数，表示设备详情API
        final RegExp deviceIdPattern = RegExp(r'/device/\d+$');
        if (deviceIdPattern.hasMatch(path)) {
          print('===== 设备详情 API 响应 =====');
          print('路径: $path');
          if (response.data != null && response.data is Map<String, dynamic>) {
            final deviceData = response.data['data'];
            if (deviceData != null && deviceData is Map<String, dynamic>) {
              print('设备ID: ${deviceData['deviceId']}');
              print('设备名称: ${deviceData['deviceName']}');
              print('设备序列号: ${deviceData['deviceSn']}');
              print('设备图片URL: ${deviceData['deviceImage']}');
            }
          }
          print('=============================');
        }
      }
      
      return response.data;
    } catch (e) {
      // 特殊日志处理 - 告警日志API
      if (path.contains('alert_log')) {
        debugPrint('【告警日志】请求失败: $e');
        debugPrint('【告警日志】错误类型: ${e.runtimeType}');
      }
      rethrow;
    }
  }
  
  // POST请求
  // path: API路径，使用完整路径如"/product"
  // data: 请求体数据，通常为Map或自定义对象
  // params: 查询参数，会自动添加到URL中
  // options: Dio请求选项，可自定义headers等
  Future<dynamic> post(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
  }) async {
    try {
      Response response = await dio.post(
        path,
        data: data,
        queryParameters: params,
        options: options,
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }
  
  // DELETE请求
  // path: API路径，使用完整路径如"/device/1"
  // data: 请求体数据（如果需要）
  // params: 查询参数，会自动添加到URL中
  // options: Dio请求选项，可自定义headers等
  Future<dynamic> delete(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
  }) async {
    try {
      Response response = await dio.delete(
        path,
        data: data,
        queryParameters: params,
        options: options,
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }
  
  // PUT请求
  // path: API路径，使用完整路径如"/device"
  // data: 请求体数据，通常包含要更新的字段
  // params: 查询参数，会自动添加到URL中
  // options: Dio请求选项，可自定义headers等
  Future<dynamic> put(
    String path, {
    dynamic data,
    Map<String, dynamic>? params,
    Options? options,
  }) async {
    try {
      Response response = await dio.put(
        path,
        data: data,
        queryParameters: params,
        options: options,
      );
      return response.data;
    } catch (e) {
      rethrow;
    }
  }
  
  /// 设置请求追踪中间件的调试模式
  /// 
  /// [enable] 是否启用全局堆栈跟踪
  /// [paths] 需要特别关注的路径列表
  /// 
  /// 示例:
  /// ```dart
  /// final httpClient = HttpClient();
  /// // 开启特定路径的调试
  /// httpClient.setRequestTracing(
  ///   enable: false,
  ///   paths: ['/user/login', '/data/sync']
  /// );
  /// 
  /// // 开启全局调试
  /// httpClient.setRequestTracing(enable: true);
  /// ```
  void setRequestTracing({bool enable = false, List<String>? paths}) {
    RequestTracingMiddleware.debugStackTrace = enable;
    if (paths != null) {
      RequestTracingMiddleware.debugPaths = paths;
    }
    
    if (kDebugMode) {
      debugPrint('请求追踪模式已${enable ? '启用' : '关闭'}');
      if (paths != null) {
        debugPrint('特别关注路径: ${paths.join(', ')}');
      }
    }
  }

  Map<String, dynamic> _buildHeaders(Map<String, dynamic>? headers) {
    if (headers == null) {
      return {};
    }
    return headers;
  }
} 